//-----------------------------------------------------------------------------
// File: StraightLineShape.cs
//
// Copyright (c) Dmitry Shuklin. All rights reserved.
//-----------------------------------------------------------------------------
using System;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using Direct3D = Microsoft.DirectX.Direct3D;

namespace ObjectiveDraw.Platform
{
	public class RayLineShape : StraightLineShape
	{
		public RayLineShape() 
		{
			this.IsRay = true;
		}
	}
	/// <summary>
	/// Summary description for LineSegmentShape.
	/// </summary>
	public class StraightLineShape : DualPointShapeBase
	{
		public StraightLineShape() 
		{
			this.IsRay = false;
		}
		public bool IsRay;

		#region IDrawerShape Members

		public override float DistanceFrom(ObjectiveDraw.Platform.DrawerChartBase control, PointF point)
		{
			DrawerChartContext context = control.Context;
			/*double SinL;
			double CosL;
			double span = (this.AbscissaEnd - this.AbscissaBegin).TotalSeconds;
			float height = this.OrdinateEnd - this.OrdinateBegin;
			
			double l = Math.Sqrt(span * span + height * height);
			
			if(l > 0)
			{
				SinL = height / l;
				CosL = span / l;
			}
			else
			{
				SinL = 0;
				CosL = 1;
			}*/

			float xo1 = OffsetFromAbscissa(control, AbscissaBegin);
			float yo1 = OffsetFromOrdinate(control, OrdinateBegin);

			float xo2 = OffsetFromAbscissa(control, AbscissaEnd);
			float yo2 = OffsetFromOrdinate(control, OrdinateEnd);

			double a1 = yo2 - yo1;
			double b1 = xo2 - xo1;
			double l1 = Math.Sqrt(a1*a1 + b1*b1);

			double dx = point.X - xo1;
			double dy = point.Y - yo1;

			if(l1 < 0.00001)
			{
				return (float)Math.Sqrt(dx*dx + dy*dy);
			}

			double SinL1 = a1 / l1;
			double CosL1 = b1 / l1;

			double da = Math.Abs(dx * SinL1 - dy * CosL1);

			if(this.IsRay)
			{
				int ss = Math.Sign(CosL1 * SinL1);
				if( ((Math.Sign(dx * SinL1 + da) != ss && ss!=0) || Math.Sign(dx * CosL1) < 0) || ((Math.Sign( dy * CosL1 - da) != ss && ss!=0) || Math.Sign(dy * SinL1) < 0)  ) 
				{
					return (float)Math.Sqrt(dx*dx + dy*dy);
				}
			}

			return (float)da;
		}

		public override void RenderShape(DrawerChartBase control, ChartInfoArgs cinfo, Cerebrum.Direct3D.Forms.RenderEventArgs re, float z)
		{
			base.RenderShape (control, cinfo, re, z);

			RenderLine(control, re, z, this.m_ForeColor, this.AbscissaBegin, this.OrdinateBegin, this.AbscissaEnd, this.OrdinateEnd, this.IsRay);
		}

		#endregion

		public static void RenderLine(ObjectiveDraw.Platform.DrawerChartBase control, Cerebrum.Direct3D.Forms.RenderEventArgs re, float z, System.Drawing.Color Color, float AbscissaBegin, float OrdinateBegin, float AbscissaEnd, float OrdinateEnd, bool IsRay)
		{
			float xo1 = OffsetFromAbscissa(control, AbscissaBegin);
			float yo1 = OffsetFromOrdinate(control, OrdinateBegin);

			float xo2 = OffsetFromAbscissa(control, AbscissaEnd);
			float yo2 = OffsetFromOrdinate(control, OrdinateEnd);

			double a1 = yo2 - yo1;
			double b1 = xo2 - xo1;
			double l1 = Math.Sqrt(a1*a1 + b1*b1);

			double SinL1 = a1 / l1;
			double CosL1 = b1 / l1;


			RenderLine(control, re, Color, z, xo1, yo1, SinL1, CosL1, IsRay);
		}
		public static void RenderLine(ObjectiveDraw.Platform.DrawerChartBase control, Cerebrum.Direct3D.Forms.RenderEventArgs re, System.Drawing.Color Color, float z, float xo1, float yo1, double SinL1, double CosL1, bool IsRay)
		{
			Microsoft.DirectX.Direct3D.Device device = re.Device;
			DrawerChartContext context = control.Context;
			
			/*double SinL;
			double CosL;
			double span = (AbscissaEnd - AbscissaBegin).TotalSeconds;
			float height = OrdinateEnd - OrdinateBegin;
			
			double l = Math.Sqrt(span * span + height * height);
			
			if(l > 0)
			{
				SinL = height / l;
				CosL = span / l;
			}
			else
			{
				SinL = 0;
				CosL = 1;
			}*/

			System.Drawing.RectangleF _view = re.ClipRectangle;

			float xL = _view.X;
			float xR = _view.X + _view.Width;
			float yT = _view.Y;
			float yB = _view.Y + _view.Height;

			float []x = new float[2];
			float []y = new float[2];
			int i = 0;

			if(Math.Abs(CosL1) > 0)
			{
				float yxL = (float)(yo1 + (xL - xo1) * SinL1 / CosL1);
				float yxR = (float)(yo1 + (xR - xo1) * SinL1 / CosL1);

				if(i < 2 && yT <= yxL && yxL < yB)
				{
					x[i] = xL;
					y[i] = yxL;
					i++;
				}

				if(i < 2 && yT < yxR && yxR <= yB)
				{
					x[i] = xR;
					y[i] = yxR;
					i++;
				}
			}
			if(Math.Abs(SinL1) > 0)
			{
				float xyT = (float)(xo1 + (yT - yo1) * CosL1 / SinL1);
				float xyB = (float)(xo1 + (yB - yo1) * CosL1 / SinL1);

				if(i < 2 && xL < xyT && xyT <= xR)
				{
					x[i] = xyT;
					y[i] = yT;
					i++;
				}

				if(i < 2 && xL <= xyB && xyB < xR)
				{
					x[i] = xyB;
					y[i] = yB;
					i++;
				}
			}

			if(i!=2) return;

			if(IsRay)
				if(xL < xo1 && xo1 < xR && yT < yo1 && yo1 < yB)
				{
					if(Math.Sign(x[0] - xo1) == Math.Sign(CosL1) && Math.Sign(y[0] - yo1) == Math.Sign(SinL1))
					{
						x[1] = xo1;
						y[1] = yo1;
					}
					else if(Math.Sign(x[1] - xo1) == Math.Sign(CosL1) && Math.Sign(y[1] - yo1) == Math.Sign(SinL1))
					{
						x[0] = xo1;
						y[0] = yo1;
					}
					else
						return;
				}
				else
				{
					if(!(Math.Sign(x[0] - xo1) == Math.Sign(CosL1) && Math.Sign(y[0] - yo1) == Math.Sign(SinL1))) return;
				}

			/*x[1] = xo1;
			y[1] = yo1;
			x[1] = (float)(xo1 + CosL1 * 100);
			y[1] = (float)(yo1 + SinL1 * 100);*/


			VertexBuffer VertexBuffer = new VertexBuffer(typeof(CustomVertex.TransformedColored), 2, device, Usage.WriteOnly, CustomVertex.TransformedColored.Format, Pool.SystemMemory);

			CustomVertex.TransformedColored[] verts = (CustomVertex.TransformedColored[])VertexBuffer.Lock(0,0); // Lock the buffer (which will return our structs)
			
			int clr = Color.ToArgb();

			verts[0].Position = new Vector4(x[0], y[0], z, 1.0f);
			verts[0].Color = clr;

			verts[1].Position = new Vector4(x[1], y[1], z, 1.0f);
			verts[1].Color = clr;


			VertexBuffer.Unlock();

			device.VertexFormat = CustomVertex.TransformedColored.Format;

			// set the vertexbuffer stream source
			device.SetStreamSource(0, VertexBuffer, 0, VertexInformation.GetFormatSize(CustomVertex.TransformedColored.Format));
			// set fill mode
			device.RenderState.FillMode = FillMode.Solid;

			//use the indices buffer
			device.DrawPrimitives(PrimitiveType.LineList, 0, 1);


			VertexBuffer.Dispose();		
		}


	}
}
